define(function(require, exports) {
	var pubjs = require('pubjs');
	var util = require('util');
	var view = require('@base/view');
	var $ = require('jquery');

	// 是否是百分比数据
	var percentPattern = /^\d+(\.\d+)?%$/;
	function isPercent(string) {
		return percentPattern.test(String(string))
	}

	// 布局计算
	var Layout = pubjs.Class.extend({
		CONSTRUCTOR: function(opts) {
			/**
			 * areas 每个子矩形面积
			 * x 父矩形横坐标
			 * y 父矩形横坐标
			 * width 父矩形宽
			 * height 父矩形高
			 */
			// var row = {
			//     x: opts.x,
			//     y: opts.y,
			//     width: opts.width,
			//     height: opts.height
			// };

			this.x = opts.x || 0;
			this.y = opts.y || 0;
			this.width = opts.width;
			this.height = opts.height;
		},
		run: function(areas) {
			var out = [];

			this._squarify(areas, {
				x: this.x,
				y: this.y,
				width: this.width,
				height: this.height
			}, out);

			return out;
		},
		_squarify: function(areas, row, out) {
			var layoutDirection = 'VERTICAL';
			var width = row.width;
			var height = row.height;
			if (row.width < row.height) {
				layoutDirection = 'HORIZONTAL';
				width = row.height;
				height = row.width;
			}
			// 把考虑方向与位置的因素剥离出来，只考虑怎么排列，运行完毕之后再修正
			var shapeArr = this._getShapeListInAbstractRow(
				areas, width, height
			);
			// 首先换算出虚拟的x、y坐标
			for (var i = 0; i < shapeArr.length; i++) {
				shapeArr[i].x = 0;
				shapeArr[i].y = 0;
				for (var j = 0; j < i; j++) {
					shapeArr[i].y += shapeArr[j].height;
				}
			}
			var nextRow = {};
			// 根据虚拟的shapeArr计算真实的小矩形
			if (layoutDirection == 'VERTICAL') {
				for (var k = 0; k < shapeArr.length; k++) {
					out.push({
						x: shapeArr[k].x + row.x,
						y: shapeArr[k].y + row.y,
						width: shapeArr[k].width,
						height: shapeArr[k].height
					});
				}
				nextRow = {
					x: shapeArr[0].width + row.x,
					y: row.y,
					width: row.width - shapeArr[0].width,
					height: row.height
				};
			} else {
				for (var l = 0; l < shapeArr.length; l++) {
					out.push({
						x: shapeArr[l].y + row.x,
						y: shapeArr[l].x + row.y,
						width: shapeArr[l].height,
						height: shapeArr[l].width
					});
				}
				nextRow = {
					x: row.x,
					y: row.y + shapeArr[0].width, // 注意是虚拟形状下的width
					width: row.width,
					height: row.height - shapeArr[0].width // 注意是虚拟形状下的width
				};
			}
			// 下一步的矩形数组要剔除已经填充过的矩形
			var nextAreaArr = areas.slice(shapeArr.length);
			if (nextAreaArr.length === 0) {
				return;
			} else {
				this._squarify(
					nextAreaArr,
					nextRow,
					out
				);
			}
		},
		_getShapeListInAbstractRow: function(areas, width, height) {
			// 如果只剩下一个了，直接返回
			if (areas.length === 1) {
				return [{
					width: width,
					height: height
				}];
			}
			// 填充进入的个数，从填充一个开始到填充所有小矩形，
			// 纵横比最优时break并保留结果
			for (var count = 1; count < areas.length; count++) {

				var shapeArr0 = this._placeFixedNumberRectangles(
					areas.slice(0, count),
					width,
					height
				);
				var shapeArr1 = this._placeFixedNumberRectangles(
					areas.slice(0, count + 1),
					width,
					height
				);
				if (this._isFirstBetter(shapeArr0, shapeArr1)) {
					return shapeArr0;
				}
			}
		},
		// 确定数量进行填充
		_placeFixedNumberRectangles: function(areaSubArr, width, height) {
			var count = areaSubArr.length;
			// 声明返回值-每个矩形的形状（长宽）之数组
			// 例如：
			/*[
					{
						width: 11
						height: 12
					},
					{
						width: 11
						height: 22
					}
				]*/
			var shapeArr = [];

			// 求出面积总和
			var sum = 0;
			for (var i = 0; i < areaSubArr.length; i++) {
				sum += areaSubArr[i];
			}
			var cellWidth = sum / height;
			for (var j = 0; j < count; j++) {
				var cellHeight = height * areaSubArr[j] / sum;
				shapeArr.push({
					width: cellWidth,
					height: cellHeight
				});
			}
			return shapeArr;
		},
		// 相邻的两种填充方式放进去，比较是不是前一个的纵横比较小
		_isFirstBetter: function(shapeArr0, shapeArr1) {
			var ratio0 = shapeArr0[0].height / shapeArr0[0].width;
			ratio0 = (ratio0 > 1) ? 1 / ratio0 : ratio0;
			var ratio1 = shapeArr1[0].height / shapeArr1[0].width;
			ratio1 = (ratio1 > 1) ? 1 / ratio1 : ratio1;
			if (Math.abs(ratio0 - 1) <= Math.abs(ratio1 - 1)) {
				return true;
			}
			return false;
		}
	});
	exports.layout = Layout;

	var Main = view.container.extend({
		init: function(config) {
			config = pubjs.conf(config, {
				'class': 'M-treemap',
				color: [
					'#00DB71', '#007ECD', '#4AD998',
					'#FF6D37', '#FF784F', '#FF8E6C',
					'#7665A0', '#7D7BAE', '#898BB4',
					'#00A1E0', '#3DB7EB', '#47CBFF',
					'#161F26', '#293A46', '#52758D',
					'#B20A1E', '#F1112C', '#F55669',
					'#B2990A', '#F1D011', '#F5DD56'
				],
				position: {         // 图形在容器中的位置
					x: 'center',    // 水平位置，可选值： left、center、right
					y: 'top'        // 垂直位置，可选值： top、middle、bottom
				},
				itemStyle: null,    // 单个矩形的样式
				width: null,
				height: null,

				limit: 12,           // 最多渲染个数
				minPercent: 5,       // 图形最小比例
				precision: 1,        // 百分比小数精度

				xField: {           // 轴左侧文字字段 可以为字符串
					field: 'name',
					format: null
				},
				yField: {           // 轴右侧数据字段, 可以为字符串
					field: 'value',
					format: null,
					percent: true   // 是否显示为百分比
				},

				url: '',
				data: null,
				param: null,
				auto_load: true,
				reqType: "websocket",
				reqMethod: "get"
			});

			this.Super('init', arguments);
		},
		afterBuild: function() {
			var c = this.getConfig();

			this.uiProxy('.M-treemapItem', 'click', 'eventItemClick');

			if (c.url && c.auto_load) {
				this.load();
			} else if (c.data) {
				this.setData(c.data);
			}
		},
		eventItemClick: function(evt) {
			var item = evt.currentTarget;
			$(item).toggleClass('M-treemapItemActive');
		},
		reset: function() {
			this.$data = null;
			this.getDOM().empty();
			return this;
		},
		setParam: function(param, replace) {
			var c = this.getConfig();
			c.param = replace ? param : util.extend(c.param, param);
			return this;
		},
		load: function() {
			var c = this.getConfig();
			if (c.url) {
				pubjs.loading.show();
				switch(c.reqType){
					case 'ajax':
						pubjs.data[c.reqMethod](c.url, c.param, this, 'onData');
					break;
					case 'websocket':
						pubjs.mc.send(c.url, c.param, this.onData.bind(this));
					break;
				}
			}

			return this;
		},
		onData: function(err, data) {
			pubjs.loading.hide();

			if (err) {
				return pubjs.alert(err.message);
			}

			this.setData(data || {});
		},
		getData: function() {
			return this.$data;
		},
		setData: function(data) {
			data = data.items;
			if (data && data.length) {
				var c = this.getConfig();
				this.$data = data;
				// 尺寸计算
				var size = this.getSize();
				var container = this.buildContainer(size);
				// 数据格式化
				var usefulData = this.transformData(data, size);
				// 矩形位置计算
				this.$layout = new Layout({
					width: size.width,
					height: size.height
				});
				var locationData = this.$layout.run(usefulData.area);

				var color = c.color.slice(0);
				util.each(locationData, function(rect, index) {
					var itemData = usefulData.data[index];
					var elem = $('<div class="M-treemapItem"></div>').appendTo(container);
					elem.width(rect.width)
						.height(rect.height)
						.html([
							'<div class="M-treemapLabel">' + itemData[0] + '</div>',
							'<div class="M-treemapValue">' + itemData[1] + '</div>'
						].join(''))
						.css(util.extend({
							'position': 'absolute',
							'left': rect.x,
							'top': rect.y,
							'background': color.shift() || '#000'
						}, c.itemStyle))
						.attr('title', itemData.slice(0, 3).join('\n'));


				}, this);
			}

			return this;

		},
		// 数据格式化，返回格式化后的数据和矩形面积数据
		transformData: function(data, size) {
			var ud;
			var c = this.getConfig();
			var xField = c.xField;
			var yField = c.yField;
			yField = util.isArray(yField) ? yField[0] : yField;
			var xFieldKey = util.isString(xField) ? xField : xField.field;
			var yFieldKey = util.isString(yField) ? yField : yField.field;

			// 先要排序
			data = data.sort(function(a, b) {
				return b[yFieldKey] - a[yFieldKey];
			});

			// 数据格式化
			var totalYValue = 0;
			var formatData = [];
			util.each(data.slice(0, c.limit || ud), function(item) {
				var xValue = item[xFieldKey];
				var yValue = item[yFieldKey];

				if (util.isFunc(xField.format)) {
					xValue = xField.format.call(this, xValue, item, c) || '-';
				}

				if (util.isFunc(yField.format)) {
					yValue = yField.format.call(this, yValue, item, c);
				}

				// 分别为 横轴数据、纵轴展示数据、纵轴原始数值、纵轴原始百分比小数、纵轴限制最小百分比小数
				formatData.push([xValue, yValue]);

				totalYValue += yValue;

			});

			// 溢出的比例
			var overflow = 0;
			// 超出最小百分比的项，多余的可以借给别人
			var loanableItems = [];
			// 限制图形最小比例
			util.each(formatData, function(item) {
				var percent = item[1] / totalYValue;

				// 过滤小于精度的值
				if (percent * 100 / Math.pow(0.1, c.precision) < 1) {
					return null;
				}

				item[3] = percent;
				item[4] = Math.max(percent, c.minPercent/100);
				if (percent > c.minPercent/100) {
					loanableItems.push(item);
				} else {
					overflow += Math.max(c.minPercent / 100 - percent, 0);
				}

			});


			// 可借出项的个数
			var loanableItemsCount = loanableItems.length;
			util.each(loanableItems, function(item, idx) {
				if (overflow > 0) {
					// 可以最多借出的比例
					var loanablePercent = Math.min(item[3] - c.minPercent/100, overflow / loanableItemsCount);
					item[4] = item[3] - loanablePercent;
					loanableItemsCount--;
					overflow -= loanablePercent;
				}
			});

			util.each(formatData, function(item) {
				// 数值转换为百分比
				if (yField.percent) {
					item[2] = item[1];
					item[1] = util.toFixed(item[3] * 100, c.precision) + '%';
				}
				// 如果还是有溢出, 均分扣除
				if (overflow > 0) {
					item[4] -= overflow / formatData.length;
				}
			});

			// 计算出每个矩形的面积数据
			var areaData = [];
			util.each(formatData, function(item) {
				areaData.push(item[4] * size.containerWidth * size.containerHeight);
			});


			return {
				data: formatData,
				area: areaData
			}
		},
		// 获取内容区域尺寸
		getSize: function() {
			var c = this.getConfig();
			var container = this.getDOM();
			var width = c.width;
			var height = c.height;
			var containerWidth = container.width();
			var containerHeight = container.height();

			// 如果未指定尺寸，则使用容器尺寸
			if (!width) {
				width = containerWidth;
				height = containerHeight
			}

			// 如果
			if (isPercent(width)) {
				width = parseInt(containerWidth * parseFloat(width) / 100, 10);
			}

			if (isPercent(height)) {
				height = parseInt(containerHeight * parseFloat(height) / 100, 10);
			}

			return {
				width: width,
				height: height,
				containerWidth: containerWidth,
				containerHeight: containerHeight
			}
		},
		// 构建图形容器，并放置到合理位置
		buildContainer: function(size) {
			var c = this.getConfig();
			var elm = this.getDOM();
			var container = $('<div class="M-treemapContainer"></div>').appendTo(elm);
			container.width(size.width).height(size.height);
			container.css('position', 'absolute');

			if (container.offsetParent() != elm) {
				elm.css('position', 'relative');
			}
			switch(c.position.x) {
				case 'left':
					container.css('left', 0);
				break;
				case 'center':
					container.css('left', (size.containerWidth - size.width) / 2);
				break;
				case 'bottom':
					container.css('right', 0);
				break;
			}

			switch(c.position.y) {
				case 'top':
					container.css('top', 0);
				break;
				case 'middle':
					container.css('top', (size.containerHeight - size.height) / 2);
				break;
				case 'bottom':
					container.css('bottom', 0);
				break;
			}
			return container;
		}
	});
	exports.main = Main;
});